package com.hjl.sr.security.token.store;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 注意：仅仅是内存的存放!!
 * 1、无法跨机器
 * 2、重启后失效
 * 3、主要注意内存泄露
 * @author pister
 * 2012-12-19 下午10:16:15
 */
public class SimpleTokenStoreService implements TokenStoreService {
	
	private ConcurrentHashMap<String, ExpiredObject> holder = new ConcurrentHashMap<String, ExpiredObject>();
	
	private AtomicBoolean initied = new AtomicBoolean(false);
	
	public void init() {
		if (!initied.compareAndSet(false, true)) {
			return;
		}
		Runnable expireThread = new Runnable() {

			public void run() {
				while (!Thread.currentThread().isInterrupted()) {
					try {
						List<String> expiredTokens = new ArrayList<String>();
						for (Map.Entry<String, ExpiredObject> entry : holder.entrySet()) {
							ExpiredObject expiredObject = entry.getValue();
							if(isExpire(expiredObject)) {
								if (expiredObject == null) {
									continue;
								}
								expiredTokens.add(expiredObject.getString());
							}
						}
						for (String token : expiredTokens) {
							holder.remove(token);
						}
						
						Thread.sleep(60000);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		};
		
		new Thread(expireThread).start();
	}
	
	public Set<String> getTokens() {
		return holder.keySet();
	}

	private static boolean isExpire(ExpiredObject expiredObject) {
		if (expiredObject == null) {
			return true;
		}
		return System.currentTimeMillis() >= expiredObject.getExpire();
	}
	
	public String delete(String token) {
		if (token == null) {
			return null;
		}
		ExpiredObject expiredObject = holder.remove(token);
		if (expiredObject == null) {
			return null;
		}
		if (isExpire(expiredObject)) {
			return null;
		}
		return expiredObject.getString();
	}

	public boolean exist(String token) {
		ExpiredObject expiredObject = holder.get(token);
		if (expiredObject == null) {
			return false;
		}
		if (isExpire(expiredObject)) {
			return false;
		}
		return true;
	}

	public void set(String token, int expireInSeconds) {
		holder.put(token, new ExpiredObject(token,(System.currentTimeMillis() + 1000 * expireInSeconds)));
	}

	static class ExpiredObject {
		private String string;
		private long expire;
		public ExpiredObject(String string, long expire) {
			super();
			this.string = string;
			this.expire = expire;
		}
		public String getString() {
			return string;
		}
		public void setString(String string) {
			this.string = string;
		}
		public long getExpire() {
			return expire;
		}
		public void setExpire(long expire) {
			this.expire = expire;
		}
	}
	
}
